﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Web;
using System.Linq;

using System.Drawing;
using System.Drawing.Imaging;

namespace Hxsoft.AppV1.Module
{
	public class WebResourceCache
	{
		private static string CacheFolderUrl = StringExtensions.GetEffectiveValueOrDefault(ConfigurationManager.AppSettings["CacheFolderUrl"], "/_Client/Upload/");

		/// <summary>
		/// 获取缓存路径信息。
		/// </summary>
		/// <param name="resourceId">资源的标识。</param>
		/// <param name="copyName">资源副本名。</param>
		/// <returns>缓存路径信息。</returns>
		private static PathInfo GetCachePathInfo(int resourceId, string copyName)
		{
			PathInfo info = new PathInfo();

			string strRid = resourceId.ToString();
			info.FileName = strRid.Substring(strRid.Length - 1) + (string.IsNullOrEmpty(copyName) ? "" : "_" + copyName);
			info.Folder = strRid.Substring(0, strRid.Length - 1);
			info.Folder = Hxsoft.StringExtensions.Join(info.Folder.ToCharArray(), "/");
			info.Folder = CacheFolderUrl + (string.IsNullOrEmpty(info.Folder) ? "" : info.Folder + "/");

			return info;
		}

		/// <summary>
		/// 写入磁盘缓存中。
		/// </summary>
		/// <param name="folderUrl">文件夹的路径。</param>
		/// <param name="fileName">文件的名称（包含扩展名）。</param>
		/// <param name="content">文件的内容。</param>
		private static void WriteToCache(string folderUrl, string fileName, byte[] content)
		{
			var context = HttpContext.Current;

			string fileUrl = folderUrl + "/" + fileName;
			string folderPath = context.Server.MapPath(folderUrl);
			string filePath = context.Server.MapPath(fileUrl);
			if (!File.Exists(filePath))
			{
				lock (filePath)
				{
					if (!File.Exists(filePath))
					{
						System.IO.Directory.CreateDirectory(folderPath);
						var stream = File.Create(filePath);
						stream.Close();
						File.WriteAllBytes(filePath, content);
					}
				}
			}
		}

		/// <summary>
		/// 获取资源缓存Url，如果缓存未生成，则生成后返回缓存Url。
		/// </summary>
		/// <param name="resourceId">资源的标识。</param>
		/// <param name="copyName">资源的副本名。</param>
		/// <param name="resourceType">资源的类别。</param>
		/// <returns>资源缓存Url。</returns>
		public static string GetResourceCacheUrl(int resourceId, string copyName, string resourceType)
		{
			var context = HttpContext.Current;
			PathInfo info = GetCachePathInfo(resourceId, copyName);
			info.FileExtension = resourceType;

			string fileFullName = info.FileFullName;
			string fileUrl = info.FilePath;
			string filePath = context.Server.MapPath(fileUrl);
			if (File.Exists(filePath)) return fileUrl;

			InfoResources.InfoResourceBaseInfo resourceInfo = InfoResources.GetBaseInfoItem(resourceId);
			if (resourceInfo == null) return string.Empty;

			info.FileExtension = resourceInfo.ResourceType;
			fileFullName = info.FileFullName;
			fileUrl = info.FilePath;
			filePath = context.Server.MapPath(fileUrl);
			if (File.Exists(filePath)) return fileUrl;

			if (!string.IsNullOrEmpty(copyName))
			{
				if (resourceInfo != null)
				{
					ResourceThumbnailCopyElement copyConfig = ApplicationConfiguration.GetResourceThumbnailCopy(copyName);
					ImageCopyGenerator copyGenerator = new ImageCopyGenerator();
					copyGenerator.ResizeType = ResizeRectangleType.ZoomOut;
					copyGenerator.Width = copyConfig.Width;
					copyGenerator.Height = copyConfig.Height;

					InfoResourceCopy copy = InfoResourceCopies.GenerateCopy(resourceInfo.ResourceId, copyName, copyGenerator);

					if (copy != null && copy.CopyContent != null)
					{
						WriteToCache(info.Folder, fileFullName, copy.CopyContent.ToArray());
					}
				}
			}
			else
			{
				InfoResource resource = InfoResources.GetItem(resourceId);
				if (resource != null && resource.Content != null)
				{
					// 水印
					if (!string.IsNullOrEmpty(resourceType) && new string[] { "png", "jpg", "gif" }.Contains(resourceType.ToLower()))
					{
						InfoResourceWatermark watermark = InfoResources.GetItemWatermark(resourceId);
						if (watermark != null && watermark.HasWatermark)	// 判断水印配置
						{
							// 图片水印
							string watermarkPath = GetWatermarkPath();
							if (!string.IsNullOrEmpty(watermarkPath))
							{
								System.Drawing.Image img = System.Drawing.Image.FromStream(new MemoryStream(resource.Content.ToArray()));
								string fn = info.FilePath;
								fn = context.Server.MapPath(fn);
								AddImageSignPic(img, fn, watermarkPath, 9, 80, 6);
								return fileUrl;
							}

							// 文字水印
							string watermarkText = GetWatermarkText();
							if (!string.IsNullOrEmpty(watermarkText))
							{
								System.Drawing.Image img = System.Drawing.Image.FromStream(new MemoryStream(resource.Content.ToArray()));
								string fn = info.FilePath;
								fn = context.Server.MapPath(fn);
								AddImageSignText(img, fn, watermarkText, 9, 80, "Tahoma", 12);
								return fileUrl;
							}
						}
					}

					WriteToCache(info.Folder, fileFullName, resource.Content.ToArray());
				}
			}

			return fileUrl;
		}

		private static string GetWatermarkText(int siteId)
		{
			Site site = Sites.GetItem(siteId);
			if (site == null) return null;

			return site.SiteName + (string.IsNullOrEmpty(site.MainDomain) ? "" : " http://" + site.MainDomain);
		}

		private static string GetWatermarkText()
		{
			int? siteId = Sites.CurrentSiteId;
			if (siteId.HasValue)
				return GetWatermarkText(siteId.Value);
			return null;
		}

		private static Dictionary<int, string> SiteWatermarkPath = new Dictionary<int, string>();
		private static string GetWatermarkPath(int siteId)
		{
			if (SiteWatermarkPath.ContainsKey(siteId))
				return SiteWatermarkPath[siteId];

			lock (SiteWatermarkPath)
			{
				if (!SiteWatermarkPath.ContainsKey(siteId))
				{
					string url = "/Watermark/" + siteId;
					string filePath = GetFirstExistFile(url + ".png", url + ".jpg", url + ".gif");
					SiteWatermarkPath[siteId] = filePath;
				}
			}

			return SiteWatermarkPath[siteId];
		}

		private static string GetWatermarkPath()
		{
			int? siteId = Sites.CurrentSiteId;
			if (siteId.HasValue)
				return GetWatermarkPath(siteId.Value);
			return null;
		}

		private static string GetFirstExistFile(params string[] files)
		{
			if (files == null) return null;

			var context = HttpContext.Current;
			foreach (string file in files)
			{
				string filePath = context.Server.MapPath(file);
				if (File.Exists(filePath)) return filePath;
			}

			return null;
		}

		/// <summary>
		/// 路径信息。
		/// </summary>
		private class PathInfo
		{
			/// <summary>
			/// 文件夹。
			/// </summary>
			public string Folder { get;set; }

			/// <summary>
			/// 文件名。
			/// </summary>
			public string FileName { get; set; }

			/// <summary>
			/// 扩展名。
			/// </summary>
			public string FileExtension { get; set; }

			/// <summary>
			/// 文件全称。（包括扩展名。）
			/// </summary>
			public string FileFullName
			{
				get
				{
					return FileName + (string.IsNullOrEmpty(FileExtension) ? "" : "." + FileExtension);
				}
			}

			/// <summary>
			/// 文件的路径。
			/// </summary>
			public string FilePath
			{
				get
				{
					if (string.IsNullOrEmpty(Folder)) return FileFullName;
					return Folder + (Folder.EndsWith("/") ? "" : "/") + FileFullName;
				}
			}
		}




		/* 以下代码来自 Discuz!NT 3.0 */
		/// <summary>
		/// 加图片水印
		/// </summary>
		/// <param name="filename">文件名</param>
		/// <param name="watermarkFilename">水印文件名</param>
		/// <param name="watermarkStatus">图片水印位置</param>
		public static void AddImageSignPic(System.Drawing.Image img, string filename, string watermarkFilename, int watermarkStatus, int quality, int watermarkTransparency)
		{
			Graphics g = Graphics.FromImage(img);
			//设置高质量插值法
			//g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
			//设置高质量,低速度呈现平滑程度
			//g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
			System.Drawing.Image watermark = new Bitmap(watermarkFilename);

			if (watermark.Height >= img.Height || watermark.Width >= img.Width)
				return;

			ImageAttributes imageAttributes = new ImageAttributes();
			ColorMap colorMap = new ColorMap();

			colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
			colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
			ColorMap[] remapTable = { colorMap };

			imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);

			float transparency = 0.5F;
			if (watermarkTransparency >= 1 && watermarkTransparency <= 10)
				transparency = (watermarkTransparency / 10.0F);


			float[][] colorMatrixElements = {
												new float[] {1.0f,  0.0f,  0.0f,  0.0f, 0.0f},
												new float[] {0.0f,  1.0f,  0.0f,  0.0f, 0.0f},
												new float[] {0.0f,  0.0f,  1.0f,  0.0f, 0.0f},
												new float[] {0.0f,  0.0f,  0.0f,  transparency, 0.0f},
												new float[] {0.0f,  0.0f,  0.0f,  0.0f, 1.0f}
											};

			ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);

			imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

			int xpos = 0;
			int ypos = 0;

			switch (watermarkStatus)
			{
				case 1:
					xpos = (int)(img.Width * (float).01);
					ypos = (int)(img.Height * (float).01);
					break;
				case 2:
					xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
					ypos = (int)(img.Height * (float).01);
					break;
				case 3:
					xpos = (int)((img.Width * (float).99) - (watermark.Width));
					ypos = (int)(img.Height * (float).01);
					break;
				case 4:
					xpos = (int)(img.Width * (float).01);
					ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
					break;
				case 5:
					xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
					ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
					break;
				case 6:
					xpos = (int)((img.Width * (float).99) - (watermark.Width));
					ypos = (int)((img.Height * (float).50) - (watermark.Height / 2));
					break;
				case 7:
					xpos = (int)(img.Width * (float).01);
					ypos = (int)((img.Height * (float).99) - watermark.Height);
					break;
				case 8:
					xpos = (int)((img.Width * (float).50) - (watermark.Width / 2));
					ypos = (int)((img.Height * (float).99) - watermark.Height);
					break;
				case 9:
					xpos = (int)((img.Width * (float).99) - (watermark.Width));
					ypos = (int)((img.Height * (float).99) - watermark.Height);
					break;
			}

			g.DrawImage(watermark, new System.Drawing.Rectangle(xpos, ypos, watermark.Width, watermark.Height), 0, 0, watermark.Width, watermark.Height, GraphicsUnit.Pixel, imageAttributes);

			ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
			ImageCodecInfo ici = null;
			foreach (ImageCodecInfo codec in codecs)
			{
				if (codec.MimeType.IndexOf("jpeg") > -1)
					ici = codec;
			}
			EncoderParameters encoderParams = new EncoderParameters();
			long[] qualityParam = new long[1];
			if (quality < 0 || quality > 100)
				quality = 80;

			qualityParam[0] = quality;

			EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityParam);
			encoderParams.Param[0] = encoderParam;

			if (ici != null)
				img.Save(filename, ici, encoderParams);
			else
				img.Save(filename);

			g.Dispose();
			img.Dispose();
			watermark.Dispose();
			imageAttributes.Dispose();
		}


		/// <summary>
		/// 增加图片文字水印
		/// </summary>
		/// <param name="filename">文件名</param>
		/// <param name="watermarkText">水印文字</param>
		/// <param name="watermarkStatus">图片水印位置</param>
		public static void AddImageSignText(System.Drawing.Image img, string filename, string watermarkText, int watermarkStatus, int quality, string fontname, int fontsize)
		{
			Graphics g = Graphics.FromImage(img);
			Font drawFont = new Font(fontname, fontsize, FontStyle.Regular, GraphicsUnit.Pixel);
			SizeF crSize;
			crSize = g.MeasureString(watermarkText, drawFont);

			float xpos = 0;
			float ypos = 0;

			switch (watermarkStatus)
			{
				case 1:
					xpos = (float)img.Width * (float).01;
					ypos = (float)img.Height * (float).01;
					break;
				case 2:
					xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
					ypos = (float)img.Height * (float).01;
					break;
				case 3:
					xpos = ((float)img.Width * (float).99) - crSize.Width;
					ypos = (float)img.Height * (float).01;
					break;
				case 4:
					xpos = (float)img.Width * (float).01;
					ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
					break;
				case 5:
					xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
					ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
					break;
				case 6:
					xpos = ((float)img.Width * (float).99) - crSize.Width;
					ypos = ((float)img.Height * (float).50) - (crSize.Height / 2);
					break;
				case 7:
					xpos = (float)img.Width * (float).01;
					ypos = ((float)img.Height * (float).99) - crSize.Height;
					break;
				case 8:
					xpos = ((float)img.Width * (float).50) - (crSize.Width / 2);
					ypos = ((float)img.Height * (float).99) - crSize.Height;
					break;
				case 9:
					xpos = ((float)img.Width * (float).99) - crSize.Width;
					ypos = ((float)img.Height * (float).99) - crSize.Height;
					break;
			}

			g.DrawString(watermarkText, drawFont, new SolidBrush(Color.White), xpos + 1, ypos + 1);
			g.DrawString(watermarkText, drawFont, new SolidBrush(Color.Black), xpos, ypos);

			ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
			ImageCodecInfo ici = null;
			foreach (ImageCodecInfo codec in codecs)
			{
				if (codec.MimeType.IndexOf("jpeg") > -1)
					ici = codec;
			}
			EncoderParameters encoderParams = new EncoderParameters();
			long[] qualityParam = new long[1];
			if (quality < 0 || quality > 100)
				quality = 80;

			qualityParam[0] = quality;

			EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityParam);
			encoderParams.Param[0] = encoderParam;

			if (ici != null)
				img.Save(filename, ici, encoderParams);
			else
				img.Save(filename);

			g.Dispose();
			img.Dispose();
		}
	}
}